package com.xiegang.orderservice.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xiegang.internalcommon.constant.CommonStatusEnum;
import com.xiegang.internalcommon.constant.IdentityStants;
import com.xiegang.internalcommon.constant.OrderConstants;
import com.xiegang.internalcommon.dto.Car;
import com.xiegang.internalcommon.dto.OrderInfo;
import com.xiegang.internalcommon.dto.PriceRule;
import com.xiegang.internalcommon.dto.ResponseResult;
import com.xiegang.internalcommon.request.OrderRequest;
import com.xiegang.internalcommon.response.OrderDriverResponse;
import com.xiegang.internalcommon.response.TerminalResponse;
import com.xiegang.internalcommon.util.RedisPrefixUtils;
import com.xiegang.orderservice.mapper.OrderInfoMapper;
import com.xiegang.orderservice.remote.ServiceDriverUserClient;
import com.xiegang.orderservice.remote.ServiceMapClient;
import com.xiegang.orderservice.remote.ServicePriceClient;
import com.xiegang.orderservice.remote.ServiceSsePushClient;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 服务类
 * </p>
 *
 * @author xieGang
 * @since 2023-04-07
 */

@Service
@Slf4j
public class OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ServicePriceClient servicePriceClient;

    @Autowired
    private ServiceDriverUserClient serviceDriverUserClient;

    @Autowired
    private ServiceMapClient serviceMapClient;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private ServiceSsePushClient serviceSsePushClient;

    public ResponseResult add(OrderRequest orderRequest) {

        ResponseResult<Boolean> availableDriver = serviceDriverUserClient.isAvailableDriver(orderRequest.getAddress());
        if (!availableDriver.getData()) {
            return ResponseResult.fail(CommonStatusEnum.CITY_DRIVER_EMPTY.getCode(), CommonStatusEnum.CITY_DRIVER_EMPTY.getMessage());

        }


        //黑名单校验
//        if(isBlackDevice(orderRequest)){
//           return ResponseResult.fail(CommonStatusEnum.DEVICE_IS_BLACK.getCode(),CommonStatusEnum.DEVICE_IS_BLACK.getMessage());
//        }

        //判断下单的城市和计价规则是否正常
        if (!isPriceRuleExists(orderRequest)) {
            return ResponseResult.fail(CommonStatusEnum.CITY_SERVICE_NOT_SERVICE.getCode(), CommonStatusEnum.CITY_SERVICE_NOT_SERVICE.getMessage());
        }

        //校验乘客是否有正在进行的订单
        if (isPassengerOrderGoingOn(orderRequest.getPassengerId()) > 0) {
            return ResponseResult.fail(CommonStatusEnum.DRIVER_GOING_ON.getCode(), CommonStatusEnum.DRIVER_GOING_ON.getMessage());
        }

        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderRequest, orderInfo);
        orderInfo.setOrderStatus(OrderConstants.ORDER_START);
        LocalDateTime now = LocalDateTime.now();
        orderInfo.setGmtCreate(now);
        orderInfo.setGmtModified(now);

        orderInfoMapper.insert(orderInfo);

        //定时任务处理
        for (int i = 1; i <5 ; i++) {
            // 派单
            int result = dispatchRealTimeOrder(orderInfo);
            if(result==1){
                break;
            }
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

        }
        return ResponseResult.success();
    }


    public int dispatchRealTimeOrder(OrderInfo orderInfo) {
        int resultInt = 0;

        String depLatitude = orderInfo.getDepLatitude();
        String depLongitude = orderInfo.getDepLongitude();

        String center = depLatitude + "," + depLongitude;

        List<Integer> radiusList = new ArrayList<>();
        radiusList.add(2000);
        radiusList.add(4000);
        radiusList.add(5000);
        ResponseResult<List<TerminalResponse>> listResponseResult = null;
        for (int i = 0; i < radiusList.size(); i++) {

            listResponseResult = serviceMapClient.aroundSearch(center, radiusList.get(i));
            log.info("在半径" + radiusList.get(i) + "内查找了车辆：" + listResponseResult.getData().size());
            if (listResponseResult.getData().size() > 0) {
                List<TerminalResponse> result = listResponseResult.getData();
                for (int j = 0; j < result.size(); j++) {
                    TerminalResponse terminalResponse = result.get(j);
                    Long carId = terminalResponse.getCarId();

                    ResponseResult<OrderDriverResponse> availableDriver = serviceDriverUserClient.getAvailableDriver(carId);
                    if (availableDriver.getCode() == CommonStatusEnum.AVAILABLE_DRIVER_TMPTY.getCode()) {
                        continue;
                    }
                    log.info("找到车辆了" + String.valueOf(availableDriver.getData()));
                    OrderDriverResponse orderDriverResponse = availableDriver.getData();
                    Long driverId = orderDriverResponse.getDriverId();

                    String lockKey = (driverId+"").intern();
                    RLock lock = redissonClient.getLock(lockKey);
                    lock.lock();

                    // 校验司机是否有正在进行的订单
                    if (isDriverOrderGoingOn(orderDriverResponse.getDriverId()) > 0) {
                        log.info(orderDriverResponse.getDriverId()+"司机有正在进行的订单");
                        lock.unlock();
                        continue;
                    }
                    // 订单直接匹配司机
                    ResponseResult<Car> carResponseResult = serviceDriverUserClient.getCarByCarId(carId);
                    Car car = carResponseResult.getData();

                    orderInfo.setDriverId(orderDriverResponse.getDriverId());
                    orderInfo.setCarId(orderDriverResponse.getCarId());
                    orderInfo.setDriverPhone(orderDriverResponse.getDriverPhone());

                    orderInfo.setReceiveOrderCarLongitude(terminalResponse.getLongitude());
                    orderInfo.setReceiveOrderCarLatitude(terminalResponse.getLatitude());
                    orderInfo.setReceiveOrderTime(LocalDateTime.now());

                    orderInfo.setLicenseId(orderDriverResponse.getLicenseId());
                    orderInfo.setVehicleNo(orderDriverResponse.getVehicleNo());
                    orderInfo.setOrderStatus(OrderConstants.DRIVER_RECEIVE_ORDER);

                    orderInfoMapper.updateById(orderInfo);

                    JSONObject driverContent = new  JSONObject();
                    driverContent.put("passengerId",orderInfo.getPassengerId());
                    driverContent.put("passengerPhone",orderInfo.getPassengerPhone());
                    driverContent.put("departure",orderInfo.getDeparture());
                    driverContent.put("depLongitude",orderInfo.getDepLongitude());
                    driverContent.put("depLatitude",orderInfo.getDepLatitude());
                    driverContent.put("destination",orderInfo.getDestination());
                    driverContent.put("destLongitude",orderInfo.getDestLongitude());
                    driverContent.put("destLatitude",orderInfo.getDestLatitude());


                    serviceSsePushClient.push(driverId, IdentityStants.DRIVER_IDENTITY,driverContent.toString());


                    JSONObject passengerContent = new  JSONObject();
                    passengerContent.put("driverId",orderInfo.getDriverId());
                    passengerContent.put("driverPhone",orderInfo.getDriverPhone());
                    passengerContent.put("vehicleNo",orderInfo.getVehicleNo());
                    passengerContent.put("rceiveOrderCarLongitude",orderInfo.getReceiveOrderCarLongitude());
                    passengerContent.put("receiveOrderCarLatitude",orderInfo.getReceiveOrderCarLatitude());
                    passengerContent.put("vehicleColor",car.getVehicleColor());
                    passengerContent.put("brand",car.getBrand());
                    passengerContent.put("model",car.getModel());

                    serviceSsePushClient.push(orderInfo.getPassengerId(), IdentityStants.PASSENGER_IDENTITY,passengerContent.toString());
                    resultInt = 1;
                    lock.unlock();
                }

            }
        }
        return resultInt;
    }


    /**
     * 乘客是否正在进行的订单
     *
     * @param passengerId
     * @return
     */
    private int isPassengerOrderGoingOn(Long passengerId) {

        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("passenger_id", passengerId);
        queryWrapper.and(wrapper -> wrapper.eq("order_status", OrderConstants.ORDER_START)
                .or().eq("order_status", OrderConstants.DRIVER_RECEIVE_ORDER)
                .or().eq("order_status", OrderConstants.DRIVER_TO_PICK_UP_PASSENGER)
                .or().eq("order_status", OrderConstants.DRIVER_ARRIVED_DEPARTURE)
                .or().eq("order_status", OrderConstants.PICK_UP_PASSENGER)
                .or().eq("order_status", OrderConstants.PASSENGER_GETOFF)
                .or().eq("order_status", OrderConstants.TO_START_PAY)
                .or().eq("order_status", OrderConstants.OVER_PAY)
        );

        Integer goingOnOrders = orderInfoMapper.selectCount(queryWrapper);

        return goingOnOrders;
    }

    /**
     * 正在进行的订单
     *
     * @param driverId
     * @return
     */
    private int isDriverOrderGoingOn(Long driverId) {

        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("driver_id", driverId);
        queryWrapper.and(wrapper -> wrapper.eq("order_status", OrderConstants.DRIVER_RECEIVE_ORDER)
                .or().eq("order_status", OrderConstants.DRIVER_TO_PICK_UP_PASSENGER)
                .or().eq("order_status", OrderConstants.DRIVER_ARRIVED_DEPARTURE)
                .or().eq("order_status", OrderConstants.PICK_UP_PASSENGER)
        );

        Integer goingOnOrders = orderInfoMapper.selectCount(queryWrapper);

        return goingOnOrders;
    }

    public boolean isPriceRuleExists(OrderRequest orderRequest) {
        String fareType = orderRequest.getFareType();
        int index = fareType.indexOf("$");
        String cityCode = fareType.substring(0, index);
        String vehicleType = fareType.substring(index + 1, fareType.length());

        PriceRule priceRule = new PriceRule();
        priceRule.setCityCode(cityCode);
        priceRule.setVehicleType(vehicleType);
        ResponseResult<Boolean> responseResult = servicePriceClient.ifExists(priceRule);
        return responseResult.getData();
    }

    public boolean isBlackDevice(OrderRequest orderRequest) {
        String deviceCodeKey = RedisPrefixUtils.blackDeviceCodePrefix + orderRequest.getDeviceCode();
        Boolean aBoolean = stringRedisTemplate.hasKey(deviceCodeKey);
        if (aBoolean) {
            String s = stringRedisTemplate.opsForValue().get(deviceCodeKey);
            int i = Integer.parseInt(s);
            if (i >= 2) {
                return true;
            } else {
                stringRedisTemplate.opsForValue().increment(deviceCodeKey);
            }
        } else {
            stringRedisTemplate.opsForValue().setIfAbsent(deviceCodeKey, "1", 1L, TimeUnit.HOURS);
        }

        return false;
    }


    public ResponseResult toPickUpPassenger(OrderRequest orderRequest){
        Long orderId = orderRequest.getOrderId();
        LocalDateTime toPickUpPassengerTime = orderRequest.getToPickUpPassengerTime();
        String toPickUpPassengerLongitude = orderRequest.getToPickUpPassengerLongitude();
        String toPickUpPassengerLatitude = orderRequest.getToPickUpPassengerLatitude();
        String toPickUpPassengerAddress = orderRequest.getToPickUpPassengerAddress();
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id",orderId);
        OrderInfo orderInfo = orderInfoMapper.selectOne(queryWrapper);

        orderInfo.setToPickUpPassengerAddress(toPickUpPassengerAddress);
        orderInfo.setToPickUpPassengerLongitude(toPickUpPassengerLongitude);
        orderInfo.setToPickUpPassengerTime(toPickUpPassengerTime);
        orderInfo.setToPickUpPassengerLatitude(toPickUpPassengerLatitude);
        orderInfo.setOrderStatus(OrderConstants.DRIVER_TO_PICK_UP_PASSENGER);
        orderInfoMapper.updateById(orderInfo);
        return ResponseResult.success();
    }

    public ResponseResult arrivedDeparture(OrderRequest orderRequest) {
        Long orderId = orderRequest.getOrderId();
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id",orderId);
        OrderInfo orderInfo = orderInfoMapper.selectOne(queryWrapper);


        orderInfo.setOrderStatus(OrderConstants.DRIVER_ARRIVED_DEPARTURE);
        orderInfo.setDriverArrivedDepartureTime(LocalDateTime.now());
        orderInfoMapper.updateById(orderInfo);
        return ResponseResult.success();
    }
}
